#pragma once 
#include "Mutex.hpp"
#include <cstddef>
#include <cstdio>
#include <ctime>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <memory>
#include <sched.h>
#include <sstream>
#include <stdlib.h>
#include <unistd.h>
namespace LogModule {
    // 这里实现的使用其实是有两种日志策略的，一种是直接打印在我们的屏幕上面（自用常见），一种是直接保存在文件里面
    // 这里就体现了我们c++的多态性了
    using namespace MutexModule;
    const std::string gsep = "\r\n"; // 这里主要还是为了兼容
    // 日志策略的父类
    class LogStrategy {
        public:
            ~LogStrategy() = default;
            virtual void SyncLog(const std::string& s) = 0;
    };
    class ConsoleLogStrategy : public LogStrategy {
        public:
            void SyncLog(const std::string& s) override {
                LockGuard lock(_mutex);
                cout << s << gsep;
            }
            ~ConsoleLogStrategy() {

            }
        private:
            Mutex _mutex;
    };
    const std::string defaultpath = "./log";
    const std::string defaultfile = "my.log";
    class FileLogStrategy : public LogStrategy {
        public:
            FileLogStrategy(const std::string& path = defaultpath, const std::string& file = defaultfile) 
            :_file(file), _path(path) {
                LockGuard lock(_mutex);
                // 判断文件是不是存在的
                if(std::filesystem::exists(_path)) {
                    return;
                }
                try {
                    std::filesystem::create_directories(_path);
                }catch(std::filesystem::filesystem_error& e) {
                    std::cerr << e.what() << "\n";
                }
            }
            void SyncLog(const std::string& s)override {
                LockGuard lock(_mutex);
                std::string filename = _path + (_path.back() == '/' ? "" : "/") + _file;
                std::ofstream out(filename, std::ios::app);
                if(!out.is_open()) {
                    return;
                }
                out << s << gsep;
                out.close();
            }
            ~FileLogStrategy() 
            {

            }
        private:
            std::string _path;
            std::string _file;
            Mutex _mutex;
    };
    // 日志的等级区分
    enum class LogLevel { // 这里加上class主要是为了限定作用域，防止域名污染
        DEBUG,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };
    std::string LevelToStr(LogLevel level) {
        switch (level)
        {
        case LogLevel::DEBUG:
            return "DEBUG";
        case LogLevel::INFO:
            return "INFO";
        case LogLevel::WARNING:
            return "WARNING";
        case LogLevel::ERROR:
            return "ERROR";
        case LogLevel::FATAL:
            return "FATAL";
        default:
            return "UNKNOWN";
        }
    }
    // 获取时间戳
    std::string GetTimeStamp() {
        time_t cur = time(nullptr); // 获取时间戳
        struct tm cur_time; // 存储时间
        localtime_r(&cur, &cur_time); // 这里的r表示的是可以重入的，线程安全的
        char timebuffer[128];
        snprintf(timebuffer, sizeof(timebuffer), "%4d-%02d-%02d %02d:%02d:%02d", cur_time.tm_year + 1900, cur_time.tm_mon + 1, cur_time.tm_mday, cur_time.tm_hour, cur_time.tm_min, cur_time.tm_sec);
        return timebuffer;
    }

    // 日志
    class Logger {
        public:
            Logger() {
                EnableConsoleLogStrategy();
            }
            void EnableFileLogStrategy() {
                _fflush_strategy = std::make_unique<FileLogStrategy>();
            }
            void EnableConsoleLogStrategy() {
                _fflush_strategy = std::make_unique<ConsoleLogStrategy>();
            }
            class LogMessage {
            public:
                LogMessage(LogLevel& level, std::string& src_name, int line_number, Logger& logger)
                :_curr_time(GetTimeStamp()), _level(level), _pid(getpid()), _src_name(src_name), _line_number(line_number), _logger(logger) {
                    std::stringstream ss;
                    ss << "[" << _curr_time << "]" << "[" << LevelToStr(_level) << "]" << "[" << _pid << "]" << "[" << _src_name << "]" << "[" << _line_number
                    << "]" << "- ";
                    _loginfo = ss.str();
                }
                template<class T>
                LogMessage& operator<<(const T& info) {
                    std::stringstream ss;
                    ss << info;
                    _loginfo += ss.str();
                    return *this;
                }
                ~LogMessage() { // 销毁打印
                    if(_logger._fflush_strategy) {
                        _logger._fflush_strategy->SyncLog(_loginfo);
                    }
                }
            private:
                std::string _curr_time;
                LogLevel _level;
                pid_t _pid;
                std::string _src_name;
                int _line_number;
                std::string _loginfo;
                Logger& _logger;
            };
            LogMessage operator()(LogLevel level, std::string name, int line) {
                return LogMessage(level, name, line, *this);
            }
            ~Logger() {

            }
        private:
            std::unique_ptr<LogStrategy> _fflush_strategy;
    };
    // 全局日志
    Logger logger;
    // 定义相关的宏
    #define LOG(level) logger(level, __FILE__, __LINE__)
    #define EnableConsoleLogStrategy() logger.EnableConsoleLogStrategy()
    #define EnableFileLogStrategy() logger.EnableFileLogStrategy()
}